%%@ author Grupp 3
%%@ version 1.5
%%@ copyright Grupp 3
%%@ doc The module contains functions for operating a database of projects.  

-module(proman).
-export([newProject/2, listProjects/1, deleteProject/2, renameProject/3]).

-include_lib("eunit/include/eunit.hrl").

%% @doc Creates a new project, with a generated unique ID, named ProjectName in the database Projects. Return ok if ProjectName is not already taken, else error.
%% @spec newProject(Projects, ProjectName) -> atom() | error
%% where 
%% 	Projects = string() + atom()
%% 	ProjectName = string() + atom()


newProject(Projects, ProjectName) ->

	dets:open_file(Projects, []),	
	
	case dets:member(Projects, ProjectName) of
	true ->
		dets:close(Projects),
		{error,"Project name already taken"};
	_ ->

	 	case dets:member(Projects, counter) of
	        false ->
			dets:insert(Projects,{counter,0}),
			dets:open_file("0", []),
           	dets:insert(Projects,{ProjectName,0}),
			dets:insert("0", {counter,1}),
			dets:insert(Projects,{counter,1}),
			dets:close("0"),
			dets:close(Projects),
			{ok, 0};
		true ->
      		[X] = dets:lookup(Projects, counter),	
          	Y = element(2,X),			
			dets:open_file(integer_to_list(Y), []),
           	dets:insert(Projects,{ProjectName,Y}),
			dets:insert(integer_to_list(Y), {counter,1}),
			dets:insert(Projects,{counter,Y+1}),
			dets:close(integer_to_list(Y)),
			dets:close(Projects),
			{ok, Y}
		end
	end.		 



%% @doc Remove the project named ProjectName from the database Projects. Return ok if the project named ProjectName exists, else error.
%% @spec deleteProject(Projects, ProjectName) -> atom() | error
%% where 
%% 	Projects = string() + atom()
%% 	ProjectName = string() + atom()


deleteProject(Projects, ProjectName) ->

    dets:open_file(Projects,[]),

    case dets:member(Projects, ProjectName) of
    true ->
	[Y] = dets:lookup(Projects, ProjectName),
	ID = element(2, Y),
 	%dets:delete(Projects, integer_to_list(ID)),
	dets:delete(Projects, ProjectName),
	file:delete(integer_to_list(ID)),
        dets:close(Projects),
	{ok, ID};
    false -> 
        dets:close(Projects),
        {error,"Project with that name doesn't exist"}
    end.




%% @doc Return a tuple with ok and a list of all existing projects in Projects
%% @spec listProjects(Projects) -> {atom(), list}
%% where 
%% 	Projects = string() + atom()


listProjects(Projects) ->

	dets:open_file(Projects,[]),
   	X = dets:match_object(Projects, {'_','_'}),
   	dets:close(Projects),
    	Y = lists:keydelete(counter, 1, X),
	Z = lists:keysort(2,Y),
 	{ok,Z}.


%% @doc Change the name of the project named ProjectName to NewProjectName. Return ok if the project named ProjectName exists, else error.
%% @spec renameProject(Projects, ProjectName, NewProjectName) -> atom() | error
%% where 
%% 	Projects = string() + atom()
%% 	ProjectName = string() + atom()
%%	NewProjectName = string() + atom()


renameProject(Projects, ProjectName, NewProjectName) ->
	
	dets:open_file(Projects,[]),
	
	case dets:member(Projects, ProjectName) of 
	true -> 
		[Y] = dets:lookup(Projects, ProjectName),
		ID = element(2, Y),
		dets:delete(Projects,ProjectName), 
		dets:insert(Projects,{NewProjectName,ID}),
		dets:close(Projects);
	_ ->
		dets:close(Projects),
		{error,"Project doesn't exist"}
	end.	


	
	%%% EUnit test cases here %%%


%Kontrollerar att det går att lägga till ett nytt projekt
new_project_test() -> 
	proman:newProject("project_test", "project1_test"),
  	?assertEqual(1, length(element(2,proman:listProjects("project_test")))),
	proman:deleteProject("project_test", "project1_test"),
	file:delete("project_test").

%Kontrollerar att man får ett error om man försöker lägga till ett projekt som redan finns
new_project_error_test() ->
	proman:newProject("project_test", "project1_test"),
	?assertMatch({error,_}, proman:newProject("project_test", "project1_test")),
	proman:deleteProject("project_test", "project1_test"),
	file:delete("project_test").	


%Kontrollerar att det går att radera ett projekt
delete_project_test() ->
	proman:newProject("project_test", "project1_test"),
	proman:deleteProject("project_test", "project1_test"),
	?assertEqual(0, length(element(2,proman:listProjects("project_test")))),
	file:delete("project_test").

%Kontrollerar att man får ett error om man försöker radera ett projekt som inte finns
delete_project_error_test() ->
	?assertMatch({error, _}, proman:deleteProject("project_test", "project1_test")),
	file:delete("project_test").


%Kontrollerar att man kan lista alla projekt
list_projects_test() ->
	proman:newProject("project_test", "project1_test"),	
	?assertEqual({ok, [{"project1_test",0}]}, proman:listProjects("project_test")),
	proman:deleteProject("project_test", "project1_test"),
	file:delete("project_test").

%Kontrollerar att det returneras en tom lista när man listar alla projekt och det inte finns några.
list_projects_empty_test() ->
	?assertEqual({ok, []}, proman:listProjects("project_test")),
	file:delete("project_test").	

%Kontrollerar att man kan byta namn på ett projekt
rename_project_test() ->
	proman:newProject("project_test", "project1_test"),
	proman:renameProject("project_test","project1_test", "project2_test"),
	?assertEqual({ok, [{"project2_test",0}]}, proman:listProjects("project_test")),
	proman:deleteProject("project_test", "project2_test"),
	file:delete("project_test").
	
%Kontrollerar att man får ett error om man försöker byta namn på ett projekt som inte finns
rename_project_error_test() ->
	?assertMatch({error,_}, proman:renameProject("project_test","project1_test", "project2_test")),
	file:delete("project_test").



